/**********************************************************************
*file:can文件
*author:残梦
*versions:V1.0
*date:2025.1.20
*note:
**********************************************************************/
#include "can_driver.h"
#include "system.h"
#include "protocol.h"

static int32_t can_FilterConfiguration(CAN_HandleTypeDef *hcan,uint32_t FilterBank,uint32_t FilterFIFOAssignment,\
                    uint32_t FilterID,uint32_t FilterMaskID,uint32_t FilterMaskRTR,\
                    uint32_t IDE,uint32_t RTR);

/******************************
@function:配置can筛选器
@param:
        FilterBank:指定要初始化的筛选器组。对于单个CAN实例(14个专用滤波器组)，该参数必须为Min_Data = 0到Max_Data = 13之间的一个数字。
                    对于双CAN实例(28个滤波器组共享)，该参数必须为Min_Data = 0 ~ Max_Data = 27之间的一个数字。
                    函数分配的是前14个给主CAN,其余给副CAN
        FilterFIFOAssignment:指定将分配给过滤器的FIFO(0或1)。该参数可以是@ref CAN_filter_FIFO的值
        FilterID:指定过滤器标识号(msb)配置。纯ID值，函数会自动打包添加相应的帧格式位
                    标准帧格式ID只有11位有效,扩展帧格式ID只有29位
        FilterMaskID:指定过滤器掩码或标识号,根据32位配置的模式(msb);标准帧格式ID只有11位有效,扩展帧格式ID只有29位
                    当FilterMaskID=0xFFFFFFFF时，表示只接收来自FilterID的数据
                    当FilterMaskID=0时,表示接收总线上任意设备的数据
        FilterMaskRTR:1--只接收RTR格式的数据,0--数据帧、遥控帧都接收
        IDE：标识符扩展位；值范围：标准帧--CAN_ID_STD,扩展帧--CAN_ID_EXT
        RTR：远程传输请求位；值范围：数据帧--CAN_RTR_DATA,遥控帧--CAN_RTR_REMOTE
@return:-1--配置失败,也可能是配置参数有误；0--成功
@remark:
******************************/
static int32_t can_FilterConfiguration(CAN_HandleTypeDef *hcan,uint32_t FilterBank,uint32_t FilterFIFOAssignment,\
                    uint32_t FilterID,uint32_t FilterMaskID,uint32_t FilterMaskRTR,\
                    uint32_t IDE,uint32_t RTR)
{
    CAN_FilterTypeDef sFilterConfig;
    uint32_t mask = 0,idFilter = 0,idFilterMask = 0,pos = 0;

    //值范围检查
    if(FilterBank > 27)return -1;
    if((FilterFIFOAssignment != CAN_FILTER_FIFO0) && (FilterFIFOAssignment != CAN_FILTER_FIFO1))return -1;
    if((IDE != CAN_ID_STD) && (IDE != CAN_ID_EXT))return -1;
    if((RTR != CAN_RTR_DATA) && (RTR != CAN_RTR_REMOTE))return -1;
    FilterMaskRTR = FilterMaskRTR?1:0;
    pos = (IDE == CAN_ID_STD)?21:3;//标准帧有效位32-21=11位,扩展帧有效位32-3=29位
    mask = ((uint32_t)0xFFFFFFFF>>pos);
    FilterID &= mask;//剔除无效ID位
    FilterMaskID &= mask;//剔除无效掩码位
    idFilter = (FilterID << pos) | IDE | RTR;
    idFilterMask = (FilterMaskID << pos) | IDE | FilterMaskRTR;

    sFilterConfig.FilterBank = FilterBank;
    sFilterConfig.FilterFIFOAssignment = FilterFIFOAssignment;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.SlaveStartFilterBank = 14;//前14个筛选号给主CAN使用

    sFilterConfig.FilterIdHigh = (idFilter & 0xFFFF0000) >> 16;
    sFilterConfig.FilterIdLow = idFilter & 0x0000FFFF;
    sFilterConfig.FilterMaskIdHigh = (idFilterMask & 0xFFFF0000) >> 16;
    sFilterConfig.FilterMaskIdLow = idFilterMask & 0x0000FFFF;
    sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
    if(HAL_CAN_ConfigFilter(hcan,&sFilterConfig) != HAL_OK)return -1;
    return 0;
}

/******************************
@function:can发送数据
@param:
        ID:接收方ID值,标准帧格式ID只有11位有效,扩展帧格式ID只有29位
        IDE：标识符扩展位；值范围：标准帧--CAN_ID_STD,扩展帧--CAN_ID_EXT
        RTR：远程传输请求位；值范围：数据帧--CAN_RTR_DATA,遥控帧--CAN_RTR_REMOTE
        BytesNumber:数据字节数；范围[1-8]
        data：待发送的数据
@return:-1--发送失败,也可能是参数有误；0--成功
@remark:
******************************/
int32_t can_SendData(CAN_HandleTypeDef *hcan,uint32_t ID,uint32_t IDE,uint32_t RTR,uint8_t BytesNumber,uint8_t *data)
{
    uint32_t pTxMailbox = 0,pos = 0;
    CAN_TxHeaderTypeDef TxMsg;

    if(HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0)return -1;//等待发送邮箱空闲
    if((IDE != CAN_ID_STD) && (IDE != CAN_ID_EXT))return -1;
    if((RTR != CAN_RTR_DATA) && (RTR != CAN_RTR_REMOTE))return -1;
    if((BytesNumber > 8) | (BytesNumber == 0))return -1;
    pos = (IDE == CAN_ID_STD)?21:3;//标准帧有效位32-21=11位,扩展帧有效位32-3=29位
    ID = ((uint32_t)0xFFFFFFFF>>pos) & ID;//剔除无效ID位
    
    TxMsg.StdId = (IDE == CAN_ID_STD)?ID:0x00;
    TxMsg.ExtId = (IDE == CAN_ID_EXT)?ID:0x00;
    TxMsg.IDE = IDE;
    TxMsg.RTR = RTR;
    TxMsg.DLC = (uint32_t)BytesNumber;

    HAL_StatusTypeDef status;
    status = HAL_CAN_AddTxMessage(hcan, &TxMsg,data, &pTxMailbox);
    if(status != HAL_OK){dLOG("error:HAL_CAN_AddTxMessage=%d\n",status);return -1;}
    return 0;
}

/******************************
@function:can数据接收读取
@param:
    hcan:待读取的can句柄
    FIFOAssignment:读取fifo的数据,参数范围：CAN_RX_FIFO0、CAN_RX_FIFO1
    rxHeader:接收消息详细数据
    data:读取到的数据
@return:数据接收字节数;小于0失败，遥控帧时为0
@remark:
******************************/
//#define dCAN_RxPrintf //接收数据打印
int32_t can_Recv_Msg(CAN_HandleTypeDef *hcan,uint32_t FIFOAssignment,CAN_RxHeaderTypeDef *rxHeader,uint8_t *data)
{
  if((FIFOAssignment != CAN_RX_FIFO0) && (FIFOAssignment != CAN_RX_FIFO1))return -1;
	if(HAL_CAN_GetRxMessage(hcan, FIFOAssignment, rxHeader, data) != HAL_OK)return -1;
    
#ifdef dCAN_RxPrintf
    dLOG("ID:%d IDE:%s RTR:%s DLC:%d Data:",((rxHeader->IDE == CAN_ID_STD)?rxHeader->StdId:rxHeader->ExtId),\
                                ((rxHeader->IDE == CAN_ID_STD)?"STD":"Ext"),\
                                ((rxHeader->RTR == CAN_RTR_DATA)?"DATA":"REMOTE"),\
                                rxHeader->DLC);
    uint8_t i = 0;
	for(i = 0; i < rxHeader->DLC; i++)printf("%d ",data[i]);
	dLOG("\n");
#endif
    return rxHeader->DLC;
}

/******************************
@function:can中断接收回调函数
@param:
@return:void
@remark:开启方法：HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
******************************/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_RxHeaderTypeDef rxHeader;
    uint8_t data[8];
    if(hcan->Instance == CAN1)
    {
        can_Recv_Msg(hcan,CAN_RX_FIFO0,&rxHeader,data);
        Protocol_Receive(eCommunicationMode_CAN,true,data,rxHeader.DLC);
    }
}

/******************************
@function:板can初始配置
@param:void
@return:void
@remark:
******************************/
void can_BoardInit(void)
{
    can_FilterConfiguration(&hcan,0,CAN_FILTER_FIFO0,1,0,1,CAN_ID_STD,CAN_RTR_DATA);//配置筛选器
    HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);//使能中断接收
    HAL_CAN_Start(&hcan);//启动CAN
}

/******************************
@function:板can1发送数据
@param:void
@return:-1--失败,0--成功
@remark:
******************************/
int32_t can_SendDataInterface(CAN_HandleTypeDef *hcan,uint8_t *data,uint16_t BytesNumber)
{
    if((data == NULL) || (BytesNumber == 0) || (BytesNumber > 8))return -1;
    if(can_SendData(hcan,0x00,CAN_ID_STD,CAN_RTR_DATA,BytesNumber,data) < 0)//发送标准帧数据给ID
    {
        return -1;
    }
    return 0;
}
